﻿using System;
using System.Drawing;
using System.ComponentModel;
using System.Drawing.Internal;
using System.Globalization;
using System.Runtime.InteropServices;

namespace JN.Utility
{
    [Serializable, StructLayout(LayoutKind.Sequential)]
    public struct RectangleD
    {
        public static readonly RectangleD Empty;
        private double x;
        private double y;
        private double width;
        private double height;

        public RectangleD(double x, double y, double width, double height)
        {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
        }

        public RectangleD(PointD location, SizeD size)
        {
            this.x = location.X;
            this.y = location.Y;
            this.width = size.Width;
            this.height = size.Height;
        }

        public static RectangleD FromLTRB(double left, double top, double right, double bottom)
        {
            return new RectangleD(left, top, right - left, bottom - top);
        }

        [Browsable(false)]
        public PointD Location
        {
            get { return new PointD(this.X, this.Y); }
            set
            {
                this.X = value.X;
                this.Y = value.Y;
            }
        }

        [Browsable(false)]
        public SizeD Size
        {
            get { return new SizeD(this.Width, this.Height); }
            set
            {
                this.Width = value.Width;
                this.Height = value.Height;
            }
        }

        public double X
        {
            get { return this.x; }
            set { this.x = value; }
        }

        public double Y
        {
            get { return this.y; }
            set { this.y = value; }
        }

        public double Width
        {
            get { return this.width; }
            set { this.width = value; }
        }

        public double Height
        {
            get { return this.height; }
            set { this.height = value; }
        }

        [Browsable(false)]
        public double Left
        {
            get { return this.X; }
        }

        [Browsable(false)]
        public double Top
        {
            get { return this.Y; }
        }

        [Browsable(false)]
        public double Right
        {
            get { return (this.X + this.Width); }
        }

        [Browsable(false)]
        public double Bottom
        {
            get { return (this.Y + this.Height); }
        }

        [Browsable(false)]
        public bool IsEmpty
        {
            get
            {
                if (this.Width > 0f)
                {
                    return (this.Height <= 0f);
                }
                return true;
            }
        }

        public override bool Equals(object obj)
        {
            if (!(obj is RectangleD))
            {
                return false;
            }
            RectangleD ef = (RectangleD)obj;
            return ((((ef.X == this.X) && (ef.Y == this.Y)) && (ef.Width == this.Width)) && (ef.Height == this.Height));
        }

        public static bool operator ==(RectangleD left, RectangleD right)
        {
            return ((((left.X == right.X) && (left.Y == right.Y)) && (left.Width == right.Width)) && (left.Height == right.Height));
        }

        public static bool operator !=(RectangleD left, RectangleD right)
        {
            return !(left == right);
        }

        public bool Contains(double x, double y)
        {
            return ((((this.X <= x) && (x < (this.X + this.Width))) && (this.Y <= y)) && (y < (this.Y + this.Height)));
        }

        public bool Contains(PointD pt)
        {
            return this.Contains(pt.X, pt.Y);
        }

        public bool Contains(RectangleD rect)
        {
            return ((((this.X <= rect.X) && ((rect.X + rect.Width) <= (this.X + this.Width))) && (this.Y <= rect.Y)) && ((rect.Y + rect.Height) <= (this.Y + this.Height)));
        }

        public override int GetHashCode()
        {
            return (int)(((((uint)this.X) ^ ((((uint)this.Y) << 13) | (((uint)this.Y) >> 0x13))) ^ ((((uint)this.Width) << 0x1a) | (((uint)this.Width) >> 6))) ^ ((((uint)this.Height) << 7) | (((uint)this.Height) >> 0x19)));
        }

        public void Inflate(double x, double y)
        {
            this.X -= x;
            this.Y -= y;
            this.Width += 2f * x;
            this.Height += 2f * y;
        }

        public void Inflate(SizeD size)
        {
            this.Inflate(size.Width, size.Height);
        }

        public static RectangleD Inflate(RectangleD rect, double x, double y)
        {
            RectangleD ef = rect;
            ef.Inflate(x, y);
            return ef;
        }

        public void Intersect(RectangleD rect)
        {
            RectangleD ef = Intersect(rect, this);
            this.X = ef.X;
            this.Y = ef.Y;
            this.Width = ef.Width;
            this.Height = ef.Height;
        }

        public static RectangleD Intersect(RectangleD a, RectangleD b)
        {
            double x = Math.Max(a.X, b.X);
            double num2 = Math.Min((double)(a.X + a.Width), (double)(b.X + b.Width));
            double y = Math.Max(a.Y, b.Y);
            double num4 = Math.Min((double)(a.Y + a.Height), (double)(b.Y + b.Height));
            if ((num2 >= x) && (num4 >= y))
            {
                return new RectangleD(x, y, num2 - x, num4 - y);
            }
            return Empty;
        }

        public bool IntersectsWith(RectangleD rect)
        {
            return ((((rect.X < (this.X + this.Width)) && (this.X < (rect.X + rect.Width))) && (rect.Y < (this.Y + this.Height))) && (this.Y < (rect.Y + rect.Height)));
        }

        public static RectangleD Union(RectangleD a, RectangleD b)
        {
            double x = Math.Min(a.X, b.X);
            double num2 = Math.Max((double)(a.X + a.Width), (double)(b.X + b.Width));
            double y = Math.Min(a.Y, b.Y);
            double num4 = Math.Max((double)(a.Y + a.Height), (double)(b.Y + b.Height));
            return new RectangleD(x, y, num2 - x, num4 - y);
        }

        public void Offset(PointD pos)
        {
            this.Offset(pos.X, pos.Y);
        }

        public void Offset(double x, double y)
        {
            this.X += x;
            this.Y += y;
        }

        //internal GPRECTF ToGPRECTF()
        //{
        //    return new GPRECTF(this.X, this.Y, this.Width, this.Height);
        //}

        public static implicit operator RectangleD(Rectangle r)
        {
            return new RectangleD((double)r.X, (double)r.Y, (double)r.Width, (double)r.Height);
        }

        public static implicit operator RectangleD(RectangleF r)
        {
            return new RectangleD((double)r.X, (double)r.Y, (double)r.Width, (double)r.Height);
        }

        public static implicit operator Rectangle(RectangleD r)
        {
            return new Rectangle(Convert.ToInt32(r.X), Convert.ToInt32(r.Y),
                Convert.ToInt32(r.Width), Convert.ToInt32(r.Height));
        }

        public static implicit operator RectangleF(RectangleD r)
        {
            return new RectangleF(Convert.ToSingle(r.X), Convert.ToSingle(r.Y), 
                Convert.ToSingle(r.Width), Convert.ToSingle(r.Height));
        }

        public static RectangleD operator + (RectangleD rect,PointF p)
        {
            return new RectangleD(rect.x + p.X, rect.y + p.Y, rect.width, rect.height);
        }

        public static RectangleD operator +(RectangleD rect, Point p)
        {
            return new RectangleD(rect.x + p.X, rect.y + p.Y, rect.width, rect.height);
        }

        public static RectangleD operator -(RectangleD rect, PointF p)
        {
            return new RectangleD(rect.x - p.X, rect.y - p.Y, rect.width, rect.height);
        }

        public static RectangleD operator -(RectangleD rect, Point p)
        {
            return new RectangleD(rect.x - p.X, rect.y - p.Y, rect.width, rect.height);
        }

        public override string ToString()
        {
            return ("{X=" + this.X.ToString(CultureInfo.CurrentCulture) + ",Y=" + this.Y.ToString(CultureInfo.CurrentCulture) + ",Width=" + this.Width.ToString(CultureInfo.CurrentCulture) + ",Height=" + this.Height.ToString(CultureInfo.CurrentCulture) + "}");
        }

        static RectangleD()
        {
            Empty = new RectangleD();
        }
    }
}
